#ifndef QLSCANDEV_H
#define QLSCANDEV_H

#include <QLibrary>
#include <QObject>
#include <QThread>
#include <QtConcurrent>

/**
 * @brief The QLsCANDev class	CAN驱动接口
 * 显示加载动态库
 */
class QLsCANDev : public QObject
{
	Q_OBJECT
public:
	#pragma pack(push, 1)

	/* CANMSG.Dat报文内容协议帧 */
	struct CANMSGDataProtocolFrame
	{
		quint8 address;		/* 起始地址		(1Byte)		0x00~0x6F		*/
		quint8 property;	/* 属性			(1Byte)		R:0x00; W:0x01	*/
		quint8 size;		/* W/R 字节数	(1Byte)		0x01~0x05		*/
		quint8 data[5];		/* 数据			(1~5Byte)					*/
	};

	/* 帧类型 */
	enum FrameType
	{
		StandardFrame = 0,	/* 标准帧 */
		ExtendedFrame = 1,	/* 扩展帧 */

		DataFrame = 0,		/* 数据帧 */
		RemoteFrame = 1		/* 远程帧 */
	};

	/* CAN通信协议 */
	struct CANMSG
	{
		quint32 id;						/* 报文ID */
		quint8 tp[2];					/* 帧类型 */
		quint8 len;						/* 报文长度 */
		CANMSGDataProtocolFrame dat;	/* 报文内容 */
	};

	#pragma pack(pop)

public:
	QLsCANDev();
	~QLsCANDev();

	/* ----- USBtoCANBUS.dll接口 ----- */
	/**
	 * @brief GetHidDevice	启动设备
	 * @param CLASS_GUID	返回设备的CLASS_GUID	长度32字节
	 * @return				是否成功
	 */
	bool GetHidDevice(QString &CLASS_GUID);

	/**
	 * @brief CloseDevice	关闭设备
	 */
	void CloseDevice();

	/**
	 * @brief SetModel		设置自测模式
	 * @param model			0 为正常模式,1 自测自发模式	(默认正常模式0)
	 * @return				是否成功
	 */
	bool SetModel(unsigned char model = 0);

	/**
	 * @brief SetModel2		设置验证模式 （厂家保留使用）
	 * @param model			0 为正常模式,1 验证模式
	 * @return				是否成功
	 */
	bool SetModel2(unsigned char model);

	/**
	 * @brief SetModel3		设置CAN接收模式
	 * @param model			0 CAN 接收关,1 CAN接收开	(默认开1)
	 * @return				是否成功
	 */
	bool SetModel3(unsigned char model = 1);

	/**
	 * @brief ReSetError	错误状态复位
	 * @return				是否成功
	 */
	bool ReSetError();

	/**
	 * @brief ReSetCAN		CAN复位
	 * @return				是否成功
	 */
	bool ReSetCAN();

	/**
	 * @brief SetBaudRate	设置波特率
	 * @param brIndex		brIndex与波特率对应关系表为 (默认设为07-500k)
	 * brIndex			00		01		02		03		04		05		06		07		08		09
	 * 波特率(BIT/S)		5K		10K		20K		50K		100K	125K	250K	500K	800K	1000K
	 * @return				是否成功
	 */
	bool SetBaudRate(unsigned char brIndex = 0x07);

	/**
	 * @brief SetSubjectID	设置地址码		()
	 * @param SubjectID		地址码，长度4字节
	 * @return				是否成功
	 */
	bool SetSubjectID(unsigned char *SubjectID);

	/**
	 * @brief SetMaskCode	设置屏蔽码
	 * @param Code			屏蔽码，长度4字节	(FF FF 7F AF)
	 * @return				是否成功
	 */
	bool SetMaskCode(unsigned char *Code);

	/**
	 * @brief SetFilterCode	设置过滤码
	 * @param Code			过滤码，长度4字节
	 * @return				是否成功
	 */
	bool SetFilterCode(unsigned char *Code);

	/**
	 * @brief RefreshStatu	刷新状态
	 * @param Buffer		状态数据，长度必须是65字节
	 * @return				是否成功
	 */
	bool RefreshStatu(unsigned char *Buffer);

	/**
	 * @brief SendCANData	发送一帧CAN数据
	 * @param addr			CAN设备地址，4字节
	 * @param ftp1			帧类型一：0标准帧,1扩展帧	(默认标准帧0x00)
	 * @param ftp2			帧类型二：0数据帧,1远程帧	(默认数据帧0x00)
	 * @param len			发送数据长度，1 - 64字节 ?-> 最大8字节
	 * @param Buffer		数据内容
	 * @return				是否成功
	 */
	bool SendCANData(unsigned int addr, unsigned char ftp1 = 0x00,unsigned char ftp2 = 0x00,
					 unsigned char len = -1, unsigned char *Buffer = nullptr);

	/**
	 * @brief RecvData		接收CAN报文数据
	 * @param canmsg		默认一次最大可返回800个报文数据
	 * @return				报文个数
	 */
	int RecvData(CANMSG *canmsg);

	/* 错误信息 */
	QString errorString() const;

	/* ----- 接收缓冲区 ----- */
	/**
	 * @brief recvListSize	接收数据帧个数
	 * @return				个数
	 */
	int recvListSize();

	/**
	 * @brief hasRecvList	是否有接收数据
	 * @return				是否有
	 */
	bool hasRecvList();

	/**
	 * @brief getRecvCANMSG	获取报文接收数据
	 * @param recvList		存入列表
	 * @param size			获取个数 负数代表全部获取
	 */
	void getRecvCANMSG(QList<QLsCANDev::CANMSG> &recvList, int size = 1);

signals:
	/* CAN接收数据 的信号 */
	void sigCANReadyRead();

private slots:
	/* CAN接收数据 的槽函数 */
	void slotCANReadData();

private:
	QLibrary *m_dllUSBtoCANBUS;		/* USBtoCANBUS.dll 动态库 */
	QString m_errorString;			/* 错误信息 */

	QThread *m_thRecv;
	QList<QLsCANDev::CANMSG> m_recvList;		/* 接收缓冲区 */
	QMutex m_recvListMutex;						/* 接收缓冲区互斥锁 */
	QLsCANDev::CANMSG m_canmsg[800];
	QFuture<void> m_thCANReadDataFuture;
	bool m_thRecvIsRunning;
};

#endif // QLSCANDEV_H
